import os
import numpy as np
import sys
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QThread, QSize
from PyQt5.QtWidgets import QMainWindow, QApplication, QInputDialog, QFileDialog, \
    QMessageBox, QColorDialog, QListWidgetItem, QTableWidgetItem, QProgressBar, \
    QRadioButton, QMdiSubWindow, QWidget, QMenu, QDialog
from PyQt5.QtGui import QIntValidator, QDoubleValidator, QRegExpValidator

from PyQt5.QtCore import QPoint, QRegExp

from OCC.Extend.DataExchange import read_iges_file, read_step_file, \
    read_stl_file, write_iges_file, write_step_file, write_stl_file

from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeSphere, BRepPrimAPI_MakeTorus, \
    BRepPrimAPI_MakeBox, BRepPrimAPI_MakeCone, BRepPrimAPI_MakeCylinder, \
    BRepPrimAPI_MakeWedge, BRepPrimAPI_MakePrism

from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Fuse, BRepAlgoAPI_Cut, BRepAlgoAPI_Common
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeVertex, BRepBuilderAPI_MakeEdge, \
    BRepBuilderAPI_MakeWire, BRepBuilderAPI_MakeFace
from OCC.Core.BRep import BRep_Tool
from OCC.Core.GC import GC_MakeSegment, GC_MakeArcOfCircle
from OCC.Core.GCE2d import GCE2d_MakeSegment
from OCC.Core.GeomAPI import geomapi_To3d

from OCC.Core.gp import gp_Pnt, gp_Pnt2d, gp_Vec, gp_Pln, gp_Ax2, gp_Dir, gp_Circ, gp_Elips

from OCC.Core.TopAbs import TopAbs_SOLID, TopAbs_EDGE, TopAbs_FACE
from OCC.Core.TopoDS import TopoDS_Compound, TopoDS_Vertex, TopoDS_Wire, TopoDS_Face

import meshio
import gmsh
import pygmsh

from geom_UI import *

from OCC.Display.backend import load_backend

load_backend("qt-pyqt5")
import OCC.Display.qtDisplay as qtDisplay
from PyQt5.uic import loadUi


class Form(QWidget):
    targetSize = [0, 0, 0]
    tmpStl = 'tmp.stl'
    tmpStp = 'tmp.stp'
    tmpDiag = None

    importFile = ''
    importFileType = ''
    meshSize = 500.
    shapeModel = None
    shapeMesh = None
    vertices = None
    facets = None
    edges = None
    ratio = 1
    head = 'x'
    up = 'z'

    def __init__(self):
        super(Form, self).__init__()
        loadUi('model.ui', self)

        gmsh.initialize()
        QApplication.setStyle('fusion')
        canvas = qtDisplay.qtViewer3d(self)
        self.display3d = canvas
        self.horizontalLayoutTarget.addWidget(canvas)
        canvas.InitDriver()  # canva的驱动,设置驱动后，才能成功display
        self.display = canvas._display
        self.display.set_bg_gradient_color([0, 128, 0], [128, 128, 128])  # 设置背景渐变色
        self.display.display_triedron()  # display black trihedron

        self.doubleValidator = QDoubleValidator(self)
        self.doubleValidator.setNotation(QDoubleValidator.StandardNotation)
        self.doubleValidator.setDecimals(2)  # 设置精度，小数点2位

        reg = QRegExp("^\d+(\.\d+)?$")
        self.regExpValidator = QRegExpValidator()
        self.regExpValidator.setRegExp(reg)

        # 必须将ContextMenuPolicy设置为Qt.CustomContextMenu
        # 否则无法使用customContextMenuRequested信号
        # self.customContextMenuRequested.connect(self.showContextMenu)

        self.contextMenu = QMenu(self)
        self.contextMenu.addAction('删除物体').triggered.connect(self.on_actionDelete_model)
        self.contextMenu.addSeparator()
        self.contextMenu.addAction('导入模型').triggered.connect(self.on_actionImportModel_triggered)
        self.contextMenu.addAction('导出模型').triggered.connect(self.on_actionExportModel_triggered)
        self.contextMenu.addSeparator()
        self.contextMenu.addAction('导入网格').triggered.connect(self.on_actionImportMesh_triggered)
        self.contextMenu.addAction('导出网格').triggered.connect(self.on_actionExportMesh_triggered)
        self.contextMenu.addAction('生成网格').triggered.connect(self.on_actionGenerateMesh_triggered)
        self.contextMenu.addAction('清除网格').triggered.connect(self.on_actionClearMesh_triggered)
        self.contextMenu.addAction('网格信息').triggered.connect(self.on_actionTargetInformation_triggered)
        self.contextMenu.addSeparator()
        self.contextMenu.addAction('提取边缘').triggered.connect(self.on_actionExtractEdges_triggered)
        self.contextMenu.addSeparator()
        self.contextMenu.addAction('生成立方体').triggered.connect(self.on_actionGenerateBox_triggered)
        self.contextMenu.addAction('生成锥体').triggered.connect(self.on_actionGenerateCone_triggered)
        self.contextMenu.addAction('生成圆环').triggered.connect(self.on_actionGenerateTorus_triggered)
        self.contextMenu.addAction('生成圆柱').triggered.connect(self.on_actionGenerateCylinder_triggered)
        self.contextMenu.addAction('生成球体').triggered.connect(self.on_actionGenerateSphere_triggered)
        self.contextMenu.addAction('生成楔形').triggered.connect(self.on_actionGenerateWedge_triggered)
        self.contextMenu.addSeparator()
        self.contextMenu.addAction('布尔剪').triggered.connect(self.on_actionBoolCut_triggered)
        self.contextMenu.addAction('布尔合并').triggered.connect(self.on_actionBoolFuse_triggered)
        self.contextMenu.addAction('布尔求交').triggered.connect(self.on_actionBoolCommon_triggered)

        try:
            self.importFile = 'delete.stl'
            self.importFileType = 'mesh'

            ext = os.path.splitext(self.importFile)[1]
            if ext == '.ply2':
                with open(self.importFile) as file:
                    fileStrings = np.array(file.read().split())
                nVertices = fileStrings[0].astype(int)
                nFacets = fileStrings[1].astype(int)
                a = fileStrings[2:2 + nVertices * 3].astype(float)
                self.vertices = np.reshape(a, (-1, 3))
                a = fileStrings[2 + nVertices * 3:2 + nVertices * 3 + nFacets * 4].astype(int)
                self.facets = np.reshape(a, (-1, 4))[:, 1:]
            elif ext == '.dat':
                with open(self.importFile) as file:
                    fileStrings = np.array(file.read().split())
                self.vertices = fileStrings[np.argwhere(fileStrings == 'GRID*') + [2, 3, 7]].astype(float)
                self.facets = fileStrings[np.argwhere(fileStrings == 'CTRIA3') + [3, 4, 5]].astype(int) - 1
            else:
                mesh = meshio.read(self.importFile)
                self.vertices = np.array(mesh.points)
                self.facets = np.zeros((0, 3), dtype=int)
                for i in mesh.cells:
                    if i.type == 'triangle':
                        self.facets = np.vstack((self.facets, np.array(i.data)))
            self.edges = None
            meshio.write_points_cells(self.tmpStl, self.vertices, [('triangle', self.facets)])
            self.shapeMesh = read_stl_file(self.tmpStl)
            self.showShape(self.shapeMesh)
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    @pyqtSlot()
    def on_Form_destroyed(self):
        print('diefjis')

    @pyqtSlot(QPoint)
    def on_modelshow_customContextMenuRequested(self, pos):
        self.contextMenu.exec(self.mapToGlobal(pos))

    def on_actionImportModel_triggered(self):
        filter = '''
              STEP(*.stp;*.step);;
              IGES(*.igs;*.iges)
              '''
        fileName = QFileDialog.getOpenFileName(filter=filter)[0]
        if fileName:
            try:
                self.importFile = fileName
                self.importFileType = 'model'
                gmsh.open(self.importFile)
                xmin, ymin, zmin, xmax, ymax, zmax = gmsh.model.getBoundingBox(-1, -1)
                self.targetSize = [xmax - xmin, ymax - ymin, zmax - zmin]
                ext = os.path.splitext(self.importFile)[1]
                if ext in ['.stp', '.step']:
                    self.shapeModel = read_step_file(self.importFile)
                elif ext in ['.igs', '.iges']:
                    self.shapeModel = read_iges_file(self.importFile)
                self.showShape(self.shapeModel)
                self.vertices = None
                self.facets = None
                self.edges = None
            except Exception as e:
                QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    def on_actionExportModel_triggered(self):
        filter = '''
              STEP(*.stp;*.step);;
              IGES(*.igs;iges)
              '''
        fileName = QFileDialog.getOpenFileName(filter=filter)[0]
        if fileName:
            try:
                ext = os.path.splitext(fileName)[1]
                if ext in ['.stp', '.step']:
                    write_step_file(self.shapeModel, fileName)
                elif ext in ['.igs', '.iges']:
                    write_iges_file(self.shapeModel, fileName)
            except Exception as e:
                QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    def on_actionImportMesh_triggered(self):
        filter = '''
            All Files(*.*);;
            Abaqus(*.inp);;
            ANSYS msh(*.msh);;
            AVS-UCD(*.avs);;
            CGNS(*.cgns);;
            DOLFIN XML(*.xml);;
            Exodus(*.e;*.exo);;
            FLAC3D(*.f3grid);;
            H5M(*.h5m);;
            Kratos/MDPA(*.mdpa);;
            Medit(*.mesh;*.meshb);;
            MED/Salome(*.med);;
            Nastran(bulkdata)(*.bdf;*.fem;*.nas);;
            Netgen(*.vol;*.vol.gz);;
            Gmsh(format versions 2.2,4.0, and 4.1)(*.msh);;
            OBJ(*.obj);;
            OFF(*.off);;
            PERMAS(*.post;*.post.gz;*.dato;*.dato.gz);;
            PLY(*.ply);;
            STL(*.stl);;
            UGRID(*.ugrid);;
            VTK(*.vtk);;
            VTU(*.vtu);;
            XDMF(*.xdmf;*.xmf);;
            Catia dat(*.dat);;
            PLY2(*.ply2)
            '''
        fileName = QFileDialog.getOpenFileName(filter=filter)[0]
        if fileName:
            try:
                self.importFile = fileName
                self.importFileType = 'mesh'

                ext = os.path.splitext(self.importFile)[1]
                if ext == '.ply2':
                    with open(fileName) as file:
                        fileStrings = np.array(file.read().split())
                    nVertices = fileStrings[0].astype(int)
                    nFacets = fileStrings[1].astype(int)
                    a = fileStrings[2:2 + nVertices * 3].astype(float)
                    self.vertices = np.reshape(a, (-1, 3))
                    a = fileStrings[2 + nVertices * 3:2 + nVertices * 3 + nFacets * 4].astype(int)
                    self.facets = np.reshape(a, (-1, 4))[:, 1:]
                elif ext == '.dat':
                    with open(fileName) as file:
                        fileStrings = np.array(file.read().split())
                    self.vertices = fileStrings[np.argwhere(fileStrings == 'GRID*') + [2, 3, 7]].astype(float)
                    self.facets = fileStrings[np.argwhere(fileStrings == 'CTRIA3') + [3, 4, 5]].astype(int) - 1
                else:
                    mesh = meshio.read(fileName)
                    self.vertices = np.array(mesh.points)
                    self.facets = np.zeros((0, 3), dtype=int)
                    for i in mesh.cells:
                        if i.type == 'triangle':
                            self.facets = np.vstack((self.facets, np.array(i.data)))
                self.edges = None
                meshio.write_points_cells(self.tmpStl, self.vertices, [('triangle', self.facets)])
                self.shapeMesh = read_stl_file(self.tmpStl)
                self.showShape(self.shapeMesh)
            except Exception as e:
                QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    def GenerateTopology_Show(self, iNumNodes, vertices_temp, iNumLines, lines_temp, iNumFacets, facets_temp, \
                              LineFlag=False, FaceFlag=False):
        #   首先构造点的拓扑，并显示
        self.display.EraseAll()  # 清空显示界面
        shape_list = []
        point_Topo = []
        for ii in range(iNumNodes):
            point_Topo.append(gp_Pnt(vertices_temp[ii, 0], vertices_temp[ii, 1], vertices_temp[ii, 2]))
            shape_list.append(BRepBuilderAPI_MakeVertex(point_Topo[ii]).Shape())

        #   其次构造边并显示
        if LineFlag:
            for ii in range(iNumLines):
                iTag1 = int(lines_temp[ii, 0] - 1)
                Point1 = point_Topo[iTag1]
                iTag2 = int(lines_temp[ii, 1] - 1)
                Point2 = point_Topo[iTag2]
                Segment1 = GC_MakeSegment(Point1, Point2)
                shape_list.append(BRepBuilderAPI_MakeEdge(Segment1.Value()).Shape())

        #   最后构造面并显示
        if FaceFlag:
            for ii in range(iNumFacets):
                Point1 = point_Topo[int(facets_temp[ii, 0] - 1)]
                Point2 = point_Topo[int(facets_temp[ii, 1] - 1)]
                Point3 = point_Topo[int(facets_temp[ii, 2] - 1)]

                Edge1 = BRepBuilderAPI_MakeEdge(GC_MakeSegment(Point1, Point2).Value())
                Edge2 = BRepBuilderAPI_MakeEdge(GC_MakeSegment(Point2, Point3).Value())
                Edge3 = BRepBuilderAPI_MakeEdge(GC_MakeSegment(Point3, Point1).Value())

                wire = BRepBuilderAPI_MakeWire(Edge1.Edge(), Edge2.Edge(), Edge3.Edge()).Shape()
                shape_list.append(BRepBuilderAPI_MakeFace(wire).Shape())

        self.shapeModel = shape_list
        self.showShape(self.shapeModel)

    def on_actionGenerateMesh_triggered(self):
        if self.importFileType == 'model':
            fileName = self.importFile
        elif self.importFileType == 'generate':
            write_step_file(self.shapeModel, self.tmpStp)
            fileName = self.tmpStp
        elif self.importFileType == 'mesh':
            QMessageBox.critical(self, '错误', '导入的目标已经是网格，无需再剖分。')
            return
        meshSize, okPressed = QInputDialog.getDouble(self, "设置网格尺寸", f"网格尺寸:", self.meshSize, decimals=4)
        if okPressed:
            self.meshSize = meshSize
            try:
                gmsh.clear()
                gmsh.model.occ.importShapes(fileName)
                gmsh.model.occ.synchronize()
                gmsh.option.setNumber("Mesh.MeshSizeMin", self.meshSize)
                gmsh.option.setNumber("Mesh.MeshSizeMax", self.meshSize * 2)

                gmsh.model.mesh.generate(2)

                gmsh.write(self.tmpStl)
                ext = os.path.splitext(self.tmpStl)[1]
                mesh = meshio.read(self.tmpStl)
                self.vertices = np.array(mesh.points)
                self.facets = np.zeros((0, 3), dtype=int)
                for i in mesh.cells:
                    if i.type == 'triangle':
                        self.facets = np.vstack((self.facets, np.array(i.data)))
                self.edges = None

                self.shapeMesh = read_stl_file(self.tmpStl)
                self.display.EraseAll()
                self.showShape(self.shapeMesh)

            except Exception as e:
                QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    def transformMesh(self):
        try:
            self.vertices = self.vertices @ self.transformMatrix() * self.ratio
            meshio.write_points_cells(self.tmpStl, self.vertices, [('triangle', self.facets)])
            self.shapeMesh = read_stl_file(self.tmpStl)
            self.showShape(self.shapeMesh)
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    @pyqtSlot()
    def on_actionExportMesh_triggered(self):
        filter = '''
            All Files(*.*);;
            Abaqus(*.inp);;
            ANSYS msh(*.msh);;
            AVS-UCD(*.avs);;
            CGNS(*.cgns);;
            DOLFIN XML(*.xml);;
            Exodus(*.e;*.exo);;
            FLAC3D(*.f3grid);;
            H5M(*.h5m);;
            Kratos/MDPA(*.mdpa);;
            Medit(*.mesh;*.meshb);;
            MED/Salome(*.med);;
            Nastran(bulkdata)(*.bdf;*.fem;*.nas);;
            Netgen(*.vol;*.vol.gz);;
            Gmsh(format versions 2.2,4.0, and 4.1)(*.msh);;
            OBJ(*.obj);;
            OFF(*.off);;
            PERMAS(*.post;*.post.gz;*.dato;*.dato.gz);;
            PLY(*.ply);;
            STL(*.stl);;
            UGRID(*.ugrid);;
            VTK(*.vtk);;
            VTU(*.vtu);;
            XDMF(*.xdmf;*.xmf)
            '''
        fileName = QFileDialog.getSaveFileName(filter=filter)[0]
        if fileName:
            try:
                meshio.write_points_cells(fileName, self.vertices, [('triangle', self.facets)])
            except Exception as e:
                QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    @pyqtSlot()
    def on_actionTargetInformation_triggered(self):
        QMessageBox.information(self, '模型和网格信息', f'''\
        导入文件：{self.importFile}
        模型尺寸：{self.targetSize}
        节点数量：{0 if self.vertices is None else self.vertices.shape[0]}
        面元数量：{0 if self.facets is None else self.facets.shape[0]}
        边缘数量：{0 if self.edges is None else self.edges.shape[0]}
        网格尺寸：{[0, 0, 0] if self.vertices is None else (self.vertices).ptp(0).tolist()}
                ''')

    @pyqtSlot()
    def on_actionExtractEdges_triggered(self):
        try:
            if self.vertices is None or self.facets is None:
                return
            facetsRange = np.arange(self.facets.shape[0])
            greater = np.greater.outer(facetsRange, facetsRange)
            tmp = np.equal.outer(self.facets[:, 0], self.facets[:, 1]) & np.equal.outer(self.facets[:, 1], self.facets[:, 0])
            tmp[greater] = False
            tmp = tmp.nonzero()
            edge1 = np.column_stack((self.facets[tmp[0], 2], self.facets[tmp[0], 0], self.facets[tmp[0], 1], self.facets[tmp[1], 2]))
            tmp = np.equal.outer(self.facets[:, 1], self.facets[:, 2]) & np.equal.outer(self.facets[:, 2], self.facets[:, 1])
            tmp[greater] = False
            tmp = tmp.nonzero()
            edge2 = np.column_stack((self.facets[tmp[0], 0], self.facets[tmp[0], 1], self.facets[tmp[0], 2], self.facets[tmp[1], 0]))
            tmp = np.equal.outer(self.facets[:, 2], self.facets[:, 0]) & np.equal.outer(self.facets[:, 0], self.facets[:, 2])
            tmp[greater] = False
            tmp = tmp.nonzero()
            edge3 = np.column_stack((self.facets[tmp[0], 1], self.facets[tmp[0], 2], self.facets[tmp[0], 0], self.facets[tmp[1], 1]))
            tmp = np.equal.outer(self.facets[:, 0], self.facets[:, 2]) & np.equal.outer(self.facets[:, 1], self.facets[:, 1])
            tmp = tmp.nonzero()
            edge4 = np.column_stack((self.facets[tmp[0], 2], self.facets[tmp[0], 0], self.facets[tmp[0], 1], self.facets[tmp[1], 0]))
            tmp = np.equal.outer(self.facets[:, 0], self.facets[:, 0]) & np.equal.outer(self.facets[:, 1], self.facets[:, 2])
            tmp = tmp.nonzero()
            edge5 = np.column_stack((self.facets[tmp[0], 2], self.facets[tmp[0], 0], self.facets[tmp[0], 1], self.facets[tmp[1], 1]))
            tmp = np.equal.outer(self.facets[:, 1], self.facets[:, 0]) & np.equal.outer(self.facets[:, 2], self.facets[:, 2])
            tmp = tmp.nonzero()
            edge6 = np.column_stack((self.facets[tmp[0], 0], self.facets[tmp[0], 1], self.facets[tmp[0], 2], self.facets[tmp[1], 1]))
            self.edges = np.vstack((edge1, edge2, edge3, edge4, edge5, edge6,))
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')
        QMessageBox.information(self, '提取完毕，模型和网格信息', f'''\
        导入文件：{self.importFile}
        节点数量：{0 if self.vertices is None else self.vertices.shape[0]}
        面元数量：{0 if self.facets is None else self.facets.shape[0]}
        边缘数量：{0 if self.edges is None else self.edges.shape[0]}
        网格尺寸：{[0, 0, 0] if self.vertices is None else (self.vertices).ptp(0).tolist()}
                ''')

    @pyqtSlot()
    def on_actionClearMesh_triggered(self):
        self.clearMesh()
        self.display.EraseAll()

    def showShape(self, shape):
        try:
            self.display.EraseAll()
            self.display.DisplayShape(shape, update=True)
            self.display.FitAll()
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    # ------------调整视图的函数-------------------
    @pyqtSlot()
    def on_pushButtonfrontview_clicked(self):
        self.display.View_Front()

    @pyqtSlot()
    def on_pushButtonleftview_clicked(self):
        self.display.View_Left()

    @pyqtSlot()
    def on_pushButtonrightview_clicked(self):
        self.display.View_Right()

    @pyqtSlot()
    def on_pushButtonrearview_clicked(self):
        self.display.View_Rear()

    @pyqtSlot()
    def on_pushButtontopview_clicked(self):
        self.display.View_Top()

    @pyqtSlot()
    def on_pushButtonbottomview_clicked(self):
        self.display.View_Bottom()

    @pyqtSlot()
    def on_pushButtonX90_clicked(self):
        try:
            self.vertices[:, [1, 2]] = np.column_stack([-self.vertices[:, 2], self.vertices[:, 1]])
            meshio.write_points_cells(self.tmpStl, self.vertices, [('triangle', self.facets)])
            self.shapeMesh = read_stl_file(self.tmpStl)
            self.showShape(self.shapeMesh)
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    @pyqtSlot()
    def on_pushButtonX270_clicked(self):
        try:
            self.vertices[:, [1, 2]] = np.column_stack([self.vertices[:, 2], -self.vertices[:, 1]])
            meshio.write_points_cells(self.tmpStl, self.vertices, [('triangle', self.facets)])
            self.shapeMesh = read_stl_file(self.tmpStl)
            self.showShape(self.shapeMesh)
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    @pyqtSlot()
    def on_pushButtonX180_clicked(self):
        try:
            self.vertices[:, [1, 2]] = -self.vertices[:, [1, 2]]
            meshio.write_points_cells(self.tmpStl, self.vertices, [('triangle', self.facets)])
            self.shapeMesh = read_stl_file(self.tmpStl)
            self.showShape(self.shapeMesh)
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    @pyqtSlot()
    def on_pushButtonY90_clicked(self):
        try:
            self.vertices[:, [2, 0]] = np.column_stack([-self.vertices[:, 0], self.vertices[:, 2]])
            meshio.write_points_cells(self.tmpStl, self.vertices, [('triangle', self.facets)])
            self.shapeMesh = read_stl_file(self.tmpStl)
            self.showShape(self.shapeMesh)
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    @pyqtSlot()
    def on_pushButtonY270_clicked(self):
        try:
            self.vertices[:, [2, 0]] = np.column_stack([self.vertices[:, 0], -self.vertices[:, 2]])
            meshio.write_points_cells(self.tmpStl, self.vertices, [('triangle', self.facets)])
            self.shapeMesh = read_stl_file(self.tmpStl)
            self.showShape(self.shapeMesh)
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    @pyqtSlot()
    def on_pushButtonY180_clicked(self):
        try:
            self.vertices[:, [2, 0]] = -self.vertices[:, [2, 0]]
            meshio.write_points_cells(self.tmpStl, self.vertices, [('triangle', self.facets)])
            self.shapeMesh = read_stl_file(self.tmpStl)
            self.showShape(self.shapeMesh)
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    @pyqtSlot()
    def on_pushButtonZ90_clicked(self):
        try:
            self.vertices[:, [0, 1]] = np.column_stack([-self.vertices[:, 1], self.vertices[:, 0]])
            meshio.write_points_cells(self.tmpStl, self.vertices, [('triangle', self.facets)])
            self.shapeMesh = read_stl_file(self.tmpStl)
            self.showShape(self.shapeMesh)
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    @pyqtSlot()
    def on_pushButtonZ270_clicked(self):
        try:
            self.vertices[:, [0, 1]] = np.column_stack([self.vertices[:, 1], -self.vertices[:, 0]])
            meshio.write_points_cells(self.tmpStl, self.vertices, [('triangle', self.facets)])
            self.shapeMesh = read_stl_file(self.tmpStl)
            self.showShape(self.shapeMesh)
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    @pyqtSlot()
    def on_pushButtonZ180_clicked(self):
        try:
            self.vertices[:, [0, 1]] = -self.vertices[:, [0, 1]]
            meshio.write_points_cells(self.tmpStl, self.vertices, [('triangle', self.facets)])
            self.shapeMesh = read_stl_file(self.tmpStl)
            self.showShape(self.shapeMesh)
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    @pyqtSlot()
    def on_pushButtonRatio_clicked(self):
        self.ratio = float(self.lineEditRatio.text())
        try:
            self.vertices = self.vertices * self.ratio
            meshio.write_points_cells(self.tmpStl, self.vertices, [('triangle', self.facets)])
            self.shapeMesh = read_stl_file(self.tmpStl)
            self.showShape(self.shapeMesh)
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    def transformMatrix(self):
        axisPair = {'x': np.array([1, 0, 0]), 'y': np.array([0, 1, 0]), 'z': np.array([0, 0, 1]), '-x': np.array([-1, 0, 0]), '-y': np.array([0, -1, 0]), '-z': np.array([0, 0, -1])}
        headAxis = axisPair[self.head]
        upAxis = axisPair[self.up]
        leftAxis = np.cross(upAxis, headAxis)
        return np.column_stack((headAxis, leftAxis, upAxis))

    def clearMesh(self):
        self.vertices = None
        self.facets = None
        self.edges = None

    # --------与模型建模和变换有关的函数-------------
    # 删除物体的函数
    def Delete_model_select(self, shapes):
        self.display.Context.EraseSelected(True)
        self.display3d.sig_topods_selected.disconnect(self.Delete_model_select)

    def on_actionDelete_model(self):
        tmpDiag = QMessageBox.information(self, "提示", "请选择要删除的物体")
        self.display3d.sig_topods_selected.connect(self.Delete_model_select)

    def on_actionGenerateBox_triggered(self):
        try:
            dialog = QDialog()
            sub_ui = loadUi("./geom_UI/block_create_diag.ui", dialog)
            sub_ui.x_lineEdit.setValidator(self.doubleValidator)
            sub_ui.y_lineEdit.setValidator(self.doubleValidator)
            sub_ui.z_lineEdit.setValidator(self.doubleValidator)
            sub_ui.len_lineEdit.setValidator(self.regExpValidator)
            sub_ui.wid_lineEdit.setValidator(self.regExpValidator)
            sub_ui.height_lineEdit.setValidator(self.regExpValidator)

            sub_ui.x_lineEdit.setText('0')
            sub_ui.y_lineEdit.setText('0')
            sub_ui.z_lineEdit.setText('0')
            sub_ui.len_lineEdit.setText('1')
            sub_ui.wid_lineEdit.setText('1')
            sub_ui.height_lineEdit.setText('1')

            if dialog.exec_():
                if (sub_ui.x_lineEdit.text() == '' or sub_ui.y_lineEdit.text() == '' or sub_ui.y_lineEdit.text() == '' \
                        or sub_ui.len_lineEdit.text() == '' or sub_ui.wid_lineEdit.text() == '' or sub_ui.height_lineEdit.text() == ''):
                    QMessageBox.warning(self, "警告", "存在无效的输入，请重新输入参数！")
                    return
                f_ox = float(sub_ui.x_lineEdit.text())
                f_oy = float(sub_ui.y_lineEdit.text())
                f_oz = float(sub_ui.z_lineEdit.text())
                f_Length = float(sub_ui.len_lineEdit.text())
                f_Width = float(sub_ui.wid_lineEdit.text())
                f_Heigth = float(sub_ui.height_lineEdit.text())

                self.shapeModel = BRepPrimAPI_MakeBox(gp_Pnt(f_ox, f_oy, f_oz), f_Length, f_Width, f_Heigth).Shape()
                self.showShape(self.shapeModel)
                self.importFileType = 'generate'
            dialog.destroy()
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    def on_actionGenerateSphere_triggered(self):
        try:
            dialog = QDialog()
            sub_ui = loadUi("./geom_UI/sphere_create_diag.ui", dialog)
            sub_ui.x_lineEdit.setValidator(self.doubleValidator)
            sub_ui.y_lineEdit.setValidator(self.doubleValidator)
            sub_ui.z_lineEdit.setValidator(self.doubleValidator)
            sub_ui.r_lineEdit.setValidator(self.regExpValidator)

            sub_ui.x_lineEdit.setText('0')
            sub_ui.y_lineEdit.setText('0')
            sub_ui.z_lineEdit.setText('0')
            sub_ui.r_lineEdit.setText('1')

            if dialog.exec_():
                if sub_ui.x_lineEdit.text() == '' or sub_ui.y_lineEdit.text() == '' or sub_ui.z_lineEdit.text() == '' \
                        or sub_ui.r_lineEdit.text() == '':
                    QMessageBox.warning(self, "警告", "存在无效的输入，请重新输入参数！")
                    return
                f_ox = float(sub_ui.x_lineEdit.text())
                f_oy = float(sub_ui.y_lineEdit.text())
                f_oz = float(sub_ui.z_lineEdit.text())
                f_r = float(sub_ui.r_lineEdit.text())

                self.shapeModel = BRepPrimAPI_MakeSphere(gp_Pnt(f_ox, f_oy, f_oz), f_r).Shape()
                self.showShape(self.shapeModel)
                self.importFileType = 'generate'

            dialog.destroy()
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    def on_actionGenerateTorus_triggered(self):
        try:
            dialog = QDialog()
            sub_ui = loadUi("./geom_UI/torus_create_diag.ui", dialog)
            sub_ui.x_lineEdit.setValidator(self.doubleValidator)
            sub_ui.y_lineEdit.setValidator(self.doubleValidator)
            sub_ui.z_lineEdit.setValidator(self.doubleValidator)
            sub_ui.R1_lineEdit.setValidator(self.regExpValidator)
            sub_ui.R2_lineEdit.setValidator(self.regExpValidator)
            sub_ui.Ang_lineEdit.setValidator(self.regExpValidator)

            sub_ui.x_lineEdit.setText('0')
            sub_ui.y_lineEdit.setText('0')
            sub_ui.z_lineEdit.setText('0')
            sub_ui.R1_lineEdit.setText('2')
            sub_ui.R2_lineEdit.setText('.5')
            sub_ui.Ang_lineEdit.setText('360')

            if dialog.exec_():
                if sub_ui.x_lineEdit.text() == '' or sub_ui.y_lineEdit.text() == '' or sub_ui.z_lineEdit.text() == '' \
                        or sub_ui.R1_lineEdit.text() == '' or sub_ui.R2_lineEdit.text() == '' or sub_ui.Ang_lineEdit.text() == '':
                    QMessageBox.warning(self, "警告", "存在无效的输入，请重新输入参数！")
                    return
                f_ox = float(sub_ui.x_lineEdit.text())
                f_oy = float(sub_ui.y_lineEdit.text())
                f_oz = float(sub_ui.z_lineEdit.text())
                f_R1 = float(sub_ui.R1_lineEdit.text())
                f_R2 = float(sub_ui.R2_lineEdit.text())
                f_Ang_rad = float(sub_ui.Ang_lineEdit.text()) / 180 * np.pi
                if sub_ui.x_dir_radioButton.isChecked():
                    Tmp_Dir = gp_Dir(1, 0, 0)
                elif sub_ui.y_dir_radioButton.isChecked():
                    Tmp_Dir = gp_Dir(0, 1, 0)
                else:
                    Tmp_Dir = gp_Dir(0, 0, 1)
                self.shapeModel = BRepPrimAPI_MakeTorus(gp_Ax2(gp_Pnt(f_ox, f_oy, f_oz), Tmp_Dir), \
                                                        f_R1, f_R2, f_Ang_rad).Shape()
                self.showShape(self.shapeModel)
                self.importFileType = 'generate'
            dialog.destroy()
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    def on_actionGenerateCone_triggered(self):
        try:
            dialog = QDialog()
            sub_ui = loadUi("./geom_UI/cone_create_diag.ui", dialog)

            sub_ui.x_lineEdit.setValidator(self.doubleValidator)
            sub_ui.y_lineEdit.setValidator(self.doubleValidator)
            sub_ui.z_lineEdit.setValidator(self.doubleValidator)
            sub_ui.R1_lineEdit.setValidator(self.regExpValidator)
            sub_ui.R2_lineEdit.setValidator(self.regExpValidator)
            sub_ui.Height_lineEdit.setValidator(self.regExpValidator)

            sub_ui.x_lineEdit.setTextf('0')
            sub_ui.y_lineEdit.setTextf('0')
            sub_ui.z_lineEdit.setTextf('0')
            sub_ui.R1_lineEdit.setTextf('2')
            sub_ui.R2_lineEdit.setTextf('1')
            sub_ui.Height_lineEdit.setTextf('1')

            if dialog.exec_():
                if sub_ui.x_lineEdit.text() == '' or sub_ui.y_lineEdit.text() == '' or sub_ui.z_lineEdit.text() == '' \
                        or sub_ui.R1_lineEdit.text() == '' or sub_ui.R2_lineEdit.text() == '' or sub_ui.Height_lineEdit.text() == '':
                    QMessageBox.warning(self, "警告", "存在无效的输入，请重新输入参数！")
                    return
                f_ox = float(sub_ui.x_lineEdit.text())
                f_oy = float(sub_ui.y_lineEdit.text())
                f_oz = float(sub_ui.z_lineEdit.text())
                f_R1 = float(sub_ui.R1_lineEdit.text())
                f_R2 = float(sub_ui.R2_lineEdit.text())
                f_Height = float(sub_ui.Height_lineEdit.text())

                if sub_ui.x_dir_radiobutton.isChecked():
                    Tmp_Dir = gp_Dir(1, 0, 0)
                elif sub_ui.y_dir_radiobutton.isChecked():
                    Tmp_Dir = gp_Dir(0, 1, 0)
                else:
                    Tmp_Dir = gp_Dir(0, 0, 1)
                self.shapeModel = BRepPrimAPI_MakeCone(gp_Ax2(gp_Pnt(f_ox, f_oy, f_oz), Tmp_Dir), \
                                                       f_R1, f_R2, f_Height).Shape()
                self.showShape(self.shapeModel)
                self.importFileType = 'generate'
            dialog.destroy()
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    def on_actionGenerateCylinder_triggered(self):
        try:
            dialog = QDialog()
            sub_ui = loadUi("./geom_UI/cylinder_create_diag.ui", dialog)
            sub_ui.x_lineEdit.setValidator(self.doubleValidator)
            sub_ui.y_lineEdit.setValidator(self.doubleValidator)
            sub_ui.z_lineEdit.setValidator(self.doubleValidator)
            sub_ui.R_lineEdit.setValidator(self.regExpValidator)
            sub_ui.Height_lineEdit.setValidator(self.regExpValidator)

            sub_ui.x_lineEdit.setText('0')
            sub_ui.y_lineEdit.setText('0')
            sub_ui.z_lineEdit.setText('0')
            sub_ui.R_lineEdit.setText('1')
            sub_ui.Height_lineEdit.setText('1')

            if dialog.exec_():
                if sub_ui.x_lineEdit.text() == '' or sub_ui.y_lineEdit.text() == '' or sub_ui.z_lineEdit.text() == '' \
                        or sub_ui.R_lineEdit.text() == '' or sub_ui.Height_lineEdit.text() == '':
                    QMessageBox.warning(self, "警告", "存在无效的输入，请重新输入参数！")
                    return
                f_ox = float(sub_ui.x_lineEdit.text())
                f_oy = float(sub_ui.y_lineEdit.text())
                f_oz = float(sub_ui.z_lineEdit.text())
                f_R = float(sub_ui.R_lineEdit.text())
                f_Height = float(sub_ui.Height_lineEdit.text())
                if sub_ui.x_dir_radioButton.isChecked():
                    Tmp_Dir = gp_Dir(1, 0, 0)
                elif sub_ui.y_dir_radioButton.isChecked():
                    Tmp_Dir = gp_Dir(0, 1, 0)
                else:
                    Tmp_Dir = gp_Dir(0, 0, 1)
                self.shapeModel = BRepPrimAPI_MakeCylinder(gp_Ax2(gp_Pnt(f_ox, f_oy, f_oz), Tmp_Dir), \
                                                           f_R, f_Height).Shape()
                self.showShape(self.shapeModel)
                self.importFileType = 'generate'

            dialog.destroy()
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    def on_actionGenerateWedge_triggered(self):
        try:
            dialog = QDialog()
            sub_ui = loadUi("./geom_UI/wedge_create_diag.ui", dialog)
            sub_ui.x_lineEdit.setValidator(self.doubleValidator)
            sub_ui.y_lineEdit.setValidator(self.doubleValidator)
            sub_ui.z_lineEdit.setValidator(self.doubleValidator)
            sub_ui.dx_lineEdit.setValidator(self.regExpValidator)
            sub_ui.dy_lineEdit.setValidator(self.regExpValidator)
            sub_ui.dz_lineEdit.setValidator(self.regExpValidator)
            sub_ui.xmin_lineEdit.setValidator(self.regExpValidator)
            sub_ui.xmax_lineEdit.setValidator(self.regExpValidator)
            sub_ui.zmin_lineEdit.setValidator(self.regExpValidator)
            sub_ui.zmax_lineEdit.setValidator(self.regExpValidator)

            sub_ui.x_lineEdit.setText('0')
            sub_ui.y_lineEdit.setText('0')
            sub_ui.z_lineEdit.setText('0')
            sub_ui.dx_lineEdit.setText('2')
            sub_ui.dy_lineEdit.setText('3')
            sub_ui.dz_lineEdit.setText('4')
            sub_ui.xmin_lineEdit.setText('0')
            sub_ui.xmax_lineEdit.setText('1')
            sub_ui.zmin_lineEdit.setText('0')
            sub_ui.zmax_lineEdit.setText('1.5')

            if dialog.exec_():
                if sub_ui.x_lineEdit.text() == '' or sub_ui.y_lineEdit.text() == '' or sub_ui.z_lineEdit.text() == '' \
                        or sub_ui.dx_lineEdit.text() == '' or sub_ui.dy_lineEdit.text() == '' or sub_ui.dz_lineEdit.text() == '' \
                        or sub_ui.xmin_lineEdit.text() == '' or sub_ui.xmax_lineEdit.text() == '' \
                        or sub_ui.zmin_lineEdit.text() == '' or sub_ui.zmax_lineEdit.text() == '':
                    QMessageBox.warning(self, "警告", "存在无效的输入，请重新输入参数！")
                    return
                f_ox = float(sub_ui.x_lineEdit.text())
                f_oy = float(sub_ui.y_lineEdit.text())
                f_oz = float(sub_ui.z_lineEdit.text())
                f_dx = float(sub_ui.dx_lineEdit.text())
                f_dy = float(sub_ui.dy_lineEdit.text())
                f_dz = float(sub_ui.dz_lineEdit.text())
                f_xmin = float(sub_ui.xmin_lineEdit.text())
                f_xmax = float(sub_ui.xmax_lineEdit.text())
                f_zmin = float(sub_ui.zmin_lineEdit.text())
                f_zmax = float(sub_ui.zmax_lineEdit.text())

                if sub_ui.x_dir_radioButton.isChecked():
                    Tmp_Dir1 = gp_Dir(1, 0, 0)
                    Tmp_Dir2 = gp_Dir(0, 1, 0)
                elif sub_ui.y_dir_radioButton.isChecked():
                    Tmp_Dir1 = gp_Dir(0, 1, 0)
                    Tmp_Dir2 = gp_Dir(0, 0, 1)
                else:
                    Tmp_Dir1 = gp_Dir(0, 0, 1)
                    Tmp_Dir2 = gp_Dir(1, 0, 0)
                self.shapeModel = BRepPrimAPI_MakeWedge(gp_Ax2(gp_Pnt(f_ox, f_oy, f_oz), Tmp_Dir1, Tmp_Dir2), \
                                                        f_dx, f_dy, f_dz, f_xmin, f_zmin, f_xmax, f_zmax).Shape()
                self.showShape(self.shapeModel)
                self.importFileType = 'generate'
            dialog.destroy()
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    # 构造布尔剪切的组合效果
    def On_select_body_Cut(self, shapes):
        for shape in shapes:
            if shape.ShapeType() == TopAbs_SOLID or type(shape) == TopoDS_Compound:
                self.Select_body.append(shape)
                self.display.Context.EraseSelected(False)
            if len(self.Select_body) == 2 and self.iCutFlag == 1:
                self.shapeModel = BRepAlgoAPI_Cut(self.Select_body[0], self.Select_body[1]).Shape()
                self.showShape(self.shapeModel)
                self.iCutFlag = 0
                self.display3d.sig_topods_selected.disconnect(self.On_select_body_Cut)

    def on_actionBoolCut_triggered(self):
        self.Select_body = []
        self.iCutFlag = 1
        self.display3d.sig_topods_selected.connect(self.On_select_body_Cut)

    # 构造布尔求和的槽函数
    def On_select_body_fuse(self, shapes):
        for shape in shapes:
            if (shape.ShapeType() == TopAbs_SOLID or type(shape) == TopoDS_Compound) and self.iFuseFlag == 1:
                self.Select_body.append(shape)
                self.display.Context.EraseSelected(False)
            if len(self.Select_body) == 2:
                self.tmpDiag = QMessageBox.question(self, "Question", "已选中两个求和物体，是否进行布尔合操作？", \
                                                    QMessageBox.Yes | QMessageBox.No)
                if self.tmpDiag == QMessageBox.Yes:
                    self.shapeModel = BRepAlgoAPI_Fuse(self.Select_body[0], self.Select_body[1]).Shape()
                elif self.tmpDiag == QMessageBox.No:
                    self.shapeModel = self.Select_body
                self.showShape(self.shapeModel)
                self.iFuseFlag = 0
                self.Select_body.clear()
                self.display3d.sig_topods_selected.disconnect(self.On_select_body_fuse)

    def on_actionBoolFuse_triggered(self):
        self.Select_body = []
        self.iFuseFlag = 1
        self.display3d.sig_topods_selected.connect(self.On_select_body_fuse)

    #   布尔求交的操作
    def On_select_body_common(self, shapes):
        for shape in shapes:
            if (shape.ShapeType() == TopAbs_SOLID or type(shape) == TopoDS_Compound) and self.iCommonFlag == 1:
                self.Select_body.append(shape)
                self.display.Context.EraseSelected(False)
            if len(self.Select_body) == 2:
                self.tmpDiag = QMessageBox.question(self, "Question", "已选中两个物体，是否进行布尔交操作？", \
                                                    QMessageBox.Yes | QMessageBox.No)
                if self.tmpDiag == QMessageBox.Yes:
                    self.shapeModel = BRepAlgoAPI_Common(self.Select_body[0], self.Select_body[1]).Shape()
                elif self.tmpDiag == QMessageBox.No:
                    self.shapeModel = self.Select_body

                self.showShape(self.shapeModel)
                self.iCommonFlag = 0
                self.Select_body.clear()
                self.display3d.sig_topods_selected.disconnect(self.On_select_body_common)

    def on_actionBoolCommon_triggered(self):
        self.Select_body = []
        self.iCommonFlag = 1
        self.display3d.sig_topods_selected.connect(self.On_select_body_common)

    # 构建二维草图中的点
    def on_actionGeneratePoint_triggered(self):
        try:
            dialog = QDialog()
            sub_ui = loadUi("./geom_UI/point_create_diag.ui", dialog)
            sub_ui.x_lineEdit.setValidator(self.doubleValidator)
            sub_ui.y_lineEdit.setValidator(self.doubleValidator)
            sub_ui.z_lineEdit.setValidator(self.doubleValidator)

            if dialog.exec_():
                if sub_ui.x_lineEdit.text() == '' or sub_ui.y_lineEdit.text() == '' or sub_ui.z_lineEdit.text() == '':
                    QMessageBox.warning(self, "警告", "存在无效的输入，请重新输入参数！")
                    return
                f_ox = float(sub_ui.x_lineEdit.text())
                f_oy = float(sub_ui.y_lineEdit.text())
                f_oz = float(sub_ui.z_lineEdit.text())
                Point_Tmep = gp_Pnt(f_ox, f_oy, f_oz)
                self.shapeModel = BRepBuilderAPI_MakeVertex(Point_Tmep).Shape()
                self.showShape(self.shapeModel)
        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    # 基于两个点，构建二维草图中的线段
    def On_select_two_vertex(self, shapes):
        for shape in shapes:
            if type(shape) == TopoDS_Vertex:
                self.Select_vertex.append(shape)

                if len(self.Select_vertex) == 2:
                    Point_temp1 = BRep_Tool.Pnt(self.Select_vertex[0])
                    Point_temp2 = BRep_Tool.Pnt(self.Select_vertex[1])
                    Segment_temp = GC_MakeSegment(Point_temp1, Point_temp2)
                    Edge_temp = BRepBuilderAPI_MakeEdge(Segment_temp.Value())
                    self.shapeModel = BRepBuilderAPI_MakeWire(Edge_temp.Edge()).Shape()
                    self.showShape(self.shapeModel)

                    self.Select_vertex.clear()  # reset
                    self.display3d.sig_topods_selected.disconnect(self.On_select_two_vertex)

    def on_actionGenerateLine_triggered(self):
        self.Select_vertex = []
        self.tmpDiag = QMessageBox.information(self, "构造线段", "请顺序选择构成线段所需的两个顶点")
        self.display3d.sig_topods_selected.connect(self.On_select_two_vertex)

    # 在二维草图中绘制圆,圆弧/椭圆
    def set_function1_of_circledraw(self):
        self.sub_ui.R_lineEdit.setEnabled(True)
        self.sub_ui.dan_lineEdit.setEnabled(True)
        self.sub_ui.R1_lineEdit.setEnabled(False)
        self.sub_ui.R2_lineEdit.setEnabled(False)

    def set_function2_of_circledraw(self):
        self.sub_ui.R_lineEdit.setEnabled(False)
        self.sub_ui.dan_lineEdit.setEnabled(False)
        self.sub_ui.R1_lineEdit.setEnabled(True)
        self.sub_ui.R2_lineEdit.setEnabled(True)

    def on_actionGenerateCircle_triggered(self):
        try:
            dialog = QDialog()
            self.sub_ui = loadUi("./geom_UI/circle_create_diag.ui", dialog)

            self.sub_ui.radioButton_circle.clicked.connect(self.set_function1_of_circledraw)
            self.sub_ui.radioButton_elips.clicked.connect(self.set_function2_of_circledraw)
            self.sub_ui.x_lineEdit.setValidator(self.doubleValidator)
            self.sub_ui.y_lineEdit.setValidator(self.doubleValidator)
            self.sub_ui.z_lineEdit.setValidator(self.doubleValidator)
            self.sub_ui.R_lineEdit.setValidator(self.regExpValidator)
            self.sub_ui.dan_lineEdit.setValidator(self.regExpValidator)
            self.sub_ui.R1_lineEdit.setValidator(self.regExpValidator)
            self.sub_ui.R2_lineEdit.setValidator(self.regExpValidator)

            if dialog.exec_():
                if self.sub_ui.x_lineEdit.text() == '' or self.sub_ui.y_lineEdit.text() == '' or self.sub_ui.z_lineEdit.text() == '':
                    QMessageBox.warning(self, "警告", "存在无效的输入，请重新输入参数！")
                    return
                f_ox = float(self.sub_ui.x_lineEdit.text())
                f_oy = float(self.sub_ui.y_lineEdit.text())
                f_oz = float(self.sub_ui.z_lineEdit.text())

                if self.sub_ui.x_dir_radioButton.isChecked():
                    Tmp_Dir = gp_Dir(1, 0, 0)
                elif self.sub_ui.y_dir_radioButton.isChecked():
                    Tmp_Dir = gp_Dir(0, 1, 0)
                else:
                    Tmp_Dir = gp_Dir(0, 0, 1)

                if self.sub_ui.radioButton_circle.isChecked():
                    if self.sub_ui.R_lineEdit.text() == '' or self.sub_ui.dan_lineEdit.text() == '':
                        QMessageBox.warning(self, "警告", "存在无效的输入，请重新输入参数！")
                        return
                    f_R = float(self.sub_ui.R_lineEdit.text())
                    f_dan = float(self.sub_ui.dan_lineEdit.text())
                    GP_Circle = gp_Circ(gp_Ax2(gp_Pnt(f_ox, f_oy, f_oz), Tmp_Dir), f_R)
                    GP_temp = GC_MakeArcOfCircle(GP_Circle, 0 / 180 * np.pi, f_dan / 180 * np.pi, True)
                    BRep_temp1 = BRepBuilderAPI_MakeEdge(GP_temp.Value())
                else:
                    if self.sub_ui.R1_lineEdit.text() == '' or self.sub_ui.R2_lineEdit.text() == '':
                        QMessageBox.warning(self, "警告", "存在无效的输入，请重新输入参数！")
                        return
                    f_R1 = float(self.sub_ui.R1_lineEdit.text())

                    f_R2 = float(self.sub_ui.R2_lineEdit.text())

                    GP_temp = gp_Elips(gp_Ax2(gp_Pnt(f_ox, f_oy, f_oz), Tmp_Dir), f_R1, f_R2)
                    BRep_temp1 = BRepBuilderAPI_MakeEdge(GP_temp)

                self.shapeModel = BRepBuilderAPI_MakeWire(BRep_temp1.Edge()).Shape()
                self.showShape(self.shapeModel)

                self.sub_ui.radioButton_circle.clicked.disconnect(self.set_function1_of_circledraw)
                self.sub_ui.radioButton_elips.clicked.disconnect(self.set_function2_of_circledraw)

        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    # ---------构造2D矩形草图----------
    def on_actionGenerate_2D_rect_triggered(self):
        try:
            dialog = QDialog()
            sub_ui = loadUi("./geom_UI/rec2D_create_diag.ui", dialog)

            sub_ui.x_lineEdit.setValidator(self.doubleValidator)
            sub_ui.y_lineEdit.setValidator(self.doubleValidator)
            sub_ui.z_lineEdit.setValidator(self.doubleValidator)
            sub_ui.len_lineEdit.setValidator(self.regExpValidator)
            sub_ui.wid_lineEdit.setValidator(self.regExpValidator)

            if dialog.exec_():
                if sub_ui.x_lineEdit.text() == '' or sub_ui.y_lineEdit.text() == '' or sub_ui.z_lineEdit.text() == '' \
                        or sub_ui.len_lineEdit.text() == '' or sub_ui.wid_lineEdit.text() == '':
                    QMessageBox.warning(self, "警告", "存在无效的输入，请重新输入参数！")
                    return

                f_ox = float(sub_ui.x_lineEdit.text())
                f_oy = float(sub_ui.y_lineEdit.text())
                f_oz = float(sub_ui.z_lineEdit.text())

                if sub_ui.x_dir_radioButton.isChecked():
                    Tmp_Dir = gp_Dir(1, 0, 0)
                elif sub_ui.y_dir_radioButton.isChecked():
                    Tmp_Dir = gp_Dir(0, 1, 0)
                else:
                    Tmp_Dir = gp_Dir(0, 0, 1)

                f_Length = float(sub_ui.len_lineEdit.text())
                f_Width = float(sub_ui.wid_lineEdit.text())

                l1 = GCE2d_MakeSegment(gp_Pnt2d(0, 0), gp_Pnt2d(0, f_Width))
                l2 = GCE2d_MakeSegment(gp_Pnt2d(0, f_Width), gp_Pnt2d(f_Length, f_Width))
                l3 = GCE2d_MakeSegment(gp_Pnt2d(f_Length, f_Width), gp_Pnt2d(f_Length, 0))
                l4 = GCE2d_MakeSegment(gp_Pnt2d(f_Length, 0), gp_Pnt2d(0, 0))

                e1 = BRepBuilderAPI_MakeEdge(geomapi_To3d(l1.Value(), gp_Pln(gp_Pnt(f_ox, f_oy, f_oz), Tmp_Dir))).Edge()
                e2 = BRepBuilderAPI_MakeEdge(geomapi_To3d(l2.Value(), gp_Pln(gp_Pnt(f_ox, f_oy, f_oz), Tmp_Dir))).Edge()
                e3 = BRepBuilderAPI_MakeEdge(geomapi_To3d(l3.Value(), gp_Pln(gp_Pnt(f_ox, f_oy, f_oz), Tmp_Dir))).Edge()
                e4 = BRepBuilderAPI_MakeEdge(geomapi_To3d(l4.Value(), gp_Pln(gp_Pnt(f_ox, f_oy, f_oz), Tmp_Dir))).Edge()

                self.shapeModel = BRepBuilderAPI_MakeWire(e1, e2, e3, e4).Shape()
                self.showShape(self.shapeModel)

        except Exception as e:
            QMessageBox.critical(self, '异常', f'{sys._getframe().f_code.co_name}\n\n{e}')

    # --------通过曲线构造一个面-↓----------------------
    def Curves_To_Face(self):
        wire_all = BRepBuilderAPI_MakeWire(self.Select_wire[0])
        if len(self.Select_wire) > 1:
            for wire in range(1, len(self.Select_wire)):
                wire_all.Add(self.Select_wire[wire])
        if not wire_all.Shape().Closed():
            QMessageBox.information(self, "提示！", "所选择的曲线无法构成封闭曲线，无法生成面！请重新选择！")
        else:
            self.shapeModel = BRepBuilderAPI_MakeFace(wire_all.Shape()).Shape()
            self.showShape(self.shapeModel)

        self.display3d.sig_topods_selected.disconnect(self.On_select_to_face)
        self.iGenerate_face_Flag = 0
        self.Select_wire = []

    def On_select_to_face(self, shapes):
        print("开始选择构成面的边")
        if self.iGenerate_face_Flag != 1:
            self.tmpDiag.buttonBox.accepted.disconnect(self.Curves_To_Face)
            return
        for shape in shapes:
            if type(shape) == TopoDS_Wire:
                iIsSameFlag = 0
                if self.Select_wire != None:
                    for wire_temp in self.Select_wire:
                        if shape.IsSame(wire_temp):
                            iIsSameFlag = 1
                            break
                    if not iIsSameFlag:
                        self.Select_wire.append(shape)
                else:
                    self.Select_wire.append(shape)
                if not self.tmpDiag.buttonBox.isEnabled():
                    self.tmpDiag.buttonBox.setEnabled(True)
                    self.tmpDiag.buttonBox.accepted.connect(self.Curves_To_Face)

    def on_actionGenerate_face_triggered(self):
        self.iGenerate_face_Flag = 1
        self.Select_wire = []
        self.tmpDiag = QDialog()
        loadUi("./geom_UI/face_create_diag.ui", self.tmpDiag)
        self.tmpDiag.setModal(False)
        self.tmpDiag.show()
        self.display3d.sig_topods_selected.connect(self.On_select_to_face)

    # --------选择需要拉伸的闭合曲线或者面↓---------------
    def To_Prism(self):
        f_Height = float(self.tmpDiag.Height_lineEdit.text())
        if self.tmpDiag.x_dir_radioButton.isChecked():
            Tmp_Vec = gp_Vec(f_Height, 0, 0)
        elif self.tmpDiag.y_dir_radioButton.isChecked():
            Tmp_Vec = gp_Vec(0, f_Height, 0)
        else:
            Tmp_Vec = gp_Vec(0, 0, f_Height)
        if len(self.Select_wire) >= 1:
            for wire in range(0, len(self.Select_wire)):
                temp = BRepPrimAPI_MakePrism(self.Select_wire[wire], Tmp_Vec)
                self.shapeModel = temp.Shape()
                self.showShape(self.shapeModel)
        if len(self.Select_face) == 1:
            temp = BRepPrimAPI_MakePrism(self.Select_face[-1], Tmp_Vec)
            self.shapeModel = temp.Shape()
            self.showShape(self.shapeModel)

        self.iPrismFlag = 0  # reset
        self.Select_wire = []
        self.Select_face = []
        self.display3d.sig_topods_selected.disconnect(self.On_select_to_prism)

    def On_select_to_prism(self, shapes):
        if self.iPrismFlag != 1:
            return
        for shape in shapes:
            if type(shape) == TopoDS_Wire:
                iIsWireSameFlag = 0
                if self.Select_wire != None:
                    for wire_temp in self.Select_wire:
                        if shape.IsSame(wire_temp):
                            iIsWireSameFlag = 1
                            break
                    if not iIsWireSameFlag:
                        self.Select_wire.append(shape)
                else:
                    self.Select_wire.append(shape)
                self.Select_wire.append(shape)
                if not self.tmpDiag.Height_lineEdit.isEnabled():
                    self.tmpDiag.Height_lineEdit.setEnabled(True)
                    self.tmpDiag.buttonBox.accepted.connect(self.To_Prism)
            elif type(shape) == TopoDS_Face:
                iIsFaceSameFlag = 0
                if self.Select_face != None:
                    for face_temp in self.Select_face:
                        if shape.IsSame(face_temp):
                            iIsFaceSameFlag = 1
                            break
                    if not iIsFaceSameFlag:
                        self.Select_face.append(shape)
                if not self.tmpDiag.Height_lineEdit.isEnabled():
                    self.tmpDiag.Height_lineEdit.setEnabled(True)
                    self.tmpDiag.buttonBox.accepted.connect(self.To_Prism)

    def on_actionPrism_triggered(self):
        self.iPrismFlag = 1
        self.iPrism_Todo_Flag = 0
        self.Select_wire = []
        self.Select_face = []

        QMessageBox.information(self, "提示", "请选择需要拉伸的曲线/平面")
        self.tmpDiag = QDialog()
        loadUi("./geom_UI/prism_diag.ui", self.tmpDiag)
        self.tmpDiag.setModal(False)
        self.tmpDiag.show()
        self.display3d.sig_topods_selected.connect(self.On_select_to_prism)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    form = Form()
    form.show()
    form.resize(form.size() + QSize(1, 0))  # 显示后，微小改变窗口尺寸，使得模型显示最大化
    form.resize(form.size() + QSize(-1, 0))  # 显示后，微小改变窗口尺寸，使得模型显示最大化
    sys.exit(app.exec_())
